home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-01-26 | 8.6 KB | 363 lines | [TEXT/EDIT] |
- \ ***** Time manager example - a 'reminder' utility
- \ J. Langowski December 87
- \
- \ Strategy: write a driver that sets up a dialog which allows
- \ to enter a time & message to display after that time. After
- \ the appointment has been entered, the driver sets up a
- \ time manager call for that appointment.
- \ The time manager routine installs a SystemTask trap patch
- \ which at the next occasion will draw an alert box containing
- \ the message to be displayed.
- \
- \ Note that we have to use the patch rather than calling
- \ the alert routine directly from our time manager task,
- \ since we can't be sure we're not in the middle of a
- \ memory manager operation when it is called.
- \
-
- only forth also assembler also mac
-
- CODE InsTime ( tmTaskPtr | -- )
- MOVE.L (A6)+,A0
- _InsTime
- RTS
- END-CODE MACH
-
- CODE PrimeTime ( tmTaskPtr count | -- )
- MOVE.L (A6)+,D0
- MOVE.L (A6)+,A0
- _PrimeTime
- RTS
- END-CODE MACH
-
- CODE RmvTime ( tmTaskPtr | -- )
- MOVE.L (A6)+,A0
- _RmvTime
- RTS
- END-CODE MACH
-
- 4ascii MENU constant "menu
- 4ascii PROC constant "proc
-
- \ *** compiler support words for external definitions ***
- : :xdef
- create -4 allot
- $4EFA w, ( JMP )
- 0 w, ( entry point to be filled later )
- 0 , ( length of routine to be filled later )
- here 6 - 76543
- ;
-
- : ;xdef { branch marker entry | -- }
- marker 76543 <> abort" xdef mismatch"
- entry branch - branch w!
- here branch - 2+ branch 2+ !
- ;
-
- : xlen 4 + @ ; ( get length word of external definition )
-
- ( *** driver header block *** )
-
- 0 CONSTANT drvrFlags
- 2 CONSTANT drvrdelay
- 4 CONSTANT drvrEMask
- 6 CONSTANT drvrMenu
- 8 CONSTANT drvrOpen
- 10 CONSTANT drvrPrime
- 12 CONSTANT drvrCtl
- 14 CONSTANT drvrStatus
- 16 CONSTANT drvrClose
- 18 CONSTANT drvrname
- 50 CONSTANT DAlength
-
- \ *** compiler support words for DA and driver definitions ***
- : :DA
- create -4 allot
- here 87654 ( start of DA block, and marker )
- 50 allot ( length of block )
- ;
-
- : ;DA { DAstart marker Ropen Rprime Rctl Rstatus Rclose
- Rflags Rdelay Remask Rmenu Rname | -- }
- marker 87654 <> abort" DA definition mismatch"
- Ropen DAStart - DAStart drvrOpen + w!
- Rprime DAStart - DAStart drvrPrime + w!
- Rctl DAStart - DAStart drvrCtl + w!
- Rstatus DAStart - DAStart drvrStatus + w!
- Rclose DAStart - DAStart drvrClose + w!
- Rflags DAStart drvrFlags + w!
- Rdelay DAStart drvrDelay + w!
- Remask DAStart drvrEmask + w!
- RMenu DAStart drvrMenu + w!
- Rname count dup DAStart drvrName + c!
- DAStart drvrName + 1+ swap
- dup 31 > if drop 31 then cmove
- here DAstart - DAStart DAlength + !
- ;
-
- : DAlen DAlength + @ ; ( get length word of external definition )
-
- \ **** DA glue macros
-
- CODE DA.prelude
- LINK A6,#-512 \ 512 bytes of local Forth stack
- MOVEM.L A0-A1,-(A7) \ save registers
- MOVE.L A6,A3 \ setup local loop return stack
- SUBA.L #256,A3 \ in the low 256 local stack bytes
- MOVE.L A0,-(A6) \ parameter block
- MOVE.L A1,-(A6) \ device control entry
- RTS \ just to indicate the MACHro stops here
- END-CODE MACH
-
- CODE DA.epilogue
- MOVE.L (A6)+,D0 \ return code
- MOVEM.L (A7)+,A0-A1 \ restore registers
- UNLK A6
- RTS
- END-CODE MACH
-
- CODE DA.Jiodone
- MOVE.L (A6)+,D0 \ return code
- MOVEM.L (A7)+,A0-A1 \ restore registers
- UNLK A6
- move.l JIODone,A0
- movem.l d4-d7/a4-a6,-(a7)
- jsr (a0)
- movem.l (a7)+,d4-d7/a4-a6
- RTS
- END-CODE MACH
-
- .TRAP _newptr,sys $A51E
-
- %0000000101001010 CONSTANT DAEmask
-
- $1B4 CONSTANT SystemTask
-
- \ __________________________________________________
- \ time manager and systemTask patch routine
- \ this routine must reside in a block allocated
- \ in the system heap through a pointer.
- \ __________________________________________________
-
- header myTask 14 allot
- 6 CONSTANT taskPtr
- HEADER myName
- DC.B 9,0,'Reminder'
- header myTrap 4 allot
- header myAlert 4 allot
- header myString 256 allot
-
- : alertMe
- MOVEM.L A0-A4/A6/D0-D7,-(A7)
- LINK A6,#-128 \ 128 bytes of local Forth stack
- (call) frontwindow windowkind + @
- 2 <> IF
- ['] myTrap @ SystemTask (call) SetTrapAddress
- ['] myString 0 0 0 (call) paramText
- ['] myAlert @ 0 (call) noteAlert drop
- ['] myAlert @ (call) freeAlert
- ['] myTask RmvTime
- ['] myTask (call) DisposPtr drop
- THEN
- UNLK A6
- MOVEM.L (A7)+,A0-A4/A6/D0-D7
- ;
-
- : wakeMe
- SystemTask (call) GetTrapAddr ['] myTrap !
- ['] alertMe SystemTask (call) SetTrapAddr
- ;
-
- header mytask.end
- ' wakeme ' mytask - CONSTANT *wakeme \ task offset
- ' myAlert ' mytask - CONSTANT *myAlert \ alertID
- ' myString ' mytask - CONSTANT *myString \ alert string
-
- \ ___________________________________________
- \ desk accessory code starts here.
- \ ___________________________________________
-
- :DA reminder
- .ALIGN
-
- ( *** main desk accessory routines *** )
- header myRes0 4 allot \ local res ID=0 offset
- header dlgText 256 allot
-
- \ redefinition of cmove to make it
- \ available locally
-
- CODE cmove
- move.l (a6)+,d0
- move.l (a6)+,a1
- move.l (a6)+,a0
- tst.l d0
- ble.s @2
- @1 move.b (a0)+,(a1)+
- subq.l #1,d0
- bne.s @1
- @2 rts
- END-CODE
-
- \ ___________________
- \ wakeup routine installation
- \ ___________________
-
- : install.wakeup
- { delay alrtID msg | procHdl hSize taskBlock -- }
-
- "proc ['] myRes0 @ (call) GetResource -> procHdl
- procHdl (call) getHandleSize -> hSize
- hSize MOVE.L (A6)+,D0
- _newPtr,sys
- MOVE.L A0,-(A6) -> taskBlock
- procHdl @ taskBlock hSize cmove
- procHdl (call) releaseResource
- \ we have made a local copy of the wakeup routine
- taskBlock dup *wakeMe + swap taskPtr + !
- msg taskBlock *myString + 256 cmove
- alrtID taskBlock *myAlert + !
- alrtID (call) CouldAlert
- taskBlock InsTime
- taskBlock delay PrimeTime
- \ now the wakeup routine will wake up after
- \ the scheduled delay.
- ;
-
- : getDrvrID { dCtlEntry | -- num }
- dCtlEntry dCtlRefNum + w@ l_ext
- 1+ negate
- ;
-
- : ownResID ( resID drvrID )
- 5 shl + -16384 +
- ;
-
- : Open { parblk dce | DAWind Res0 -- returncode }
- 5 (call) sysbeep
- \ to get attention if automatically opened
- 0 dce getDrvrID ownResID -> Res0
- dce dCtlWindow + @ -> DAWind
- DAWind 0= IF ( not open already )
- Res0 ['] myRes0 !
- Res0 0 -1 (call) getNewDialog -> DAWind
- DAWind dce dCtlWindow + ! \ store dialog pointer
- DAWind dce dCtlRefNum + w@ swap windowKind + w!
- ELSE
- DAWind (call) selectWindow
- THEN
- 0
- ;
-
- : Close { parblk dce | -- returncode }
- dce dCtlWindow +
- dup @ (call) DisposDialog
- 0 swap ! ( so that Open will work again )
- 0
- ;
-
- : dialog-handler
- { dlgPtr itemHit |
- itemType hItem rBox seconds -- }
-
- \ we get here if the OK button in the dialog
- \ has been hit, therefore itemHit is always =1
- \ - in our case. But it is nice to have itemHit
- \ available, to be more general.
- \ item #3 contains the appointment message
- \ item #4 contains the delay in seconds
- \ (decimal number string)
-
- dlgPtr 4 ^ itemType ^ hItem ^ rBox (call) GetDItem
- hItem ['] dlgText (call) GetIText
- ['] dlgText (call) StringToNum -> seconds
- seconds 0> IF
- dlgPtr 3 ^ itemType ^ hItem ^ rBox
- (call) GetDItem
- hItem ['] dlgText (call) GetIText
- seconds 1000 w*
- ['] myres0 @ ['] dlgText install.wakeup
- ELSE 10 (call) sysbeep
- THEN
- ;
-
- : Ctl { parblk dce | DAWind event-rec dlgPtr itemHit -- returncode }
-
- dce dCtlWindow + @ -> DAWind
-
- parblk csCode + w@ l_ext
- CASE
- accEvent OF
- 2 DAWind windowKind + w! \ set to dialog window
- parblk csParam + @ -> event-rec
- event-rec (call) IsDialogEvent
- IF event-rec ^ dlgPtr ^ itemHit
- (call) Dialogselect
- IF dlgPtr itemHit dialog-handler THEN
- THEN
- DAWind dce dCtlRefNum + w@
- swap windowKind + w! \ reset windowkind
- ENDOF
-
- ENDCASE
- 0
- ;
-
-
- : DrOpen DA.Prelude Open DA.Epilogue ;
- : DrClose DA.Prelude Close DA.Epilogue ;
- : DrCtl DA.Prelude Ctl DA.JioDone ;
- : DrStatus ;
- : DrPrime ;
-
- ' DrOpen ' DrPrime ' DrCtl ' DrStatus ' DrClose
- $7400 \ need lock, need time, need goodbye, ctl calls
- 60 DAEmask 0 \ delay mask menu
- " Reminder" \ name
- ;DA
-
-
- ( write resource to file )
- : $create-res ( str-addr - errcode )
- call CreateResFile
- call ResError L_ext
- ;
-
- : $open-res { addr | refNum - refNum or errcode }
- addr call OpenResFile -> refNum
- call ResError L_ext
- ?dup IF ELSE refNum THEN
- ;
-
- : close-res ( refNum - errcode )
- call CloseResFile
- call ResError L_ext
- ;
-
- : make-res { addr len rtype ID name | -- }
- addr len call PtrToHand
- abort" Could not create resource handle"
- rtype ID name call AddResource
- ;
-
- : write-out { filename | refnum -- }
- filename $create-res abort" That resource file already exists"
- filename $open-res
- dup 0< abort" Open resource file failed"
- -> refnum
- refnum call UseResFile
- ['] reminder dup DALen
- "drvr 12 " Reminder" make-res
- ['] myTask ['] mytask.end over -
- "proc -16000 " wakeUp" make-res
- "proc -16000 call GetResource
- dup 80 call SetResAttrs ( 64: sysheap + 16: locked )
- call ChangedResource
- refnum close-res abort" Could not close resource file"
- ;
-
- : make-DA
- " Reminder.rsrc" $delete drop
- " Reminder.rsrc" write-out
- ;
-